#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <cstring>
#include <iostream>
#include <sstream>
#include <string>
#include <cmath>

#include <nng/nng.h>
#include <nng/protocol/pubsub0/pub.h>

#include <jomoo_utils/comm/packet_pubsub_clientserver.h>
#include <jomoo_utils/proto/msg_lake_test.h>

#define PROXY_SEND_URL "tcp://0.0.0.0:3328"

static void
fatal(const char *msg, ...)
{
	va_list ap;
	va_start(ap, msg);
	vfprintf(stderr, msg, ap);
	va_end(ap);
	fprintf(stderr, "\n");
	exit(1);
}






void sendloop_new(nng_socket sock) {
	const char* data_template = "This is data to send: A message from behind the Great Wall.";

	//strlen(data)

	size_t datalen = 0;

	uint32_t counter = 0;

	for (;;) {
		int          rv;
		nng_msg* msg;

		std::stringstream ss;
		ss << data_template << " " << (counter++);
		std::string data_str = ss.str();
		const char * data = data_str.c_str();
		datalen = data_str.size();

		if (((rv = nng_msg_alloc(&msg, 0)) != 0) ||
			((rv = nng_msg_append(msg, data, datalen)) != 0)) {
			fatal(nng_strerror(rv));
		}

		if ((rv = nng_sendmsg(sock, msg, 0)) != 0) {
			fatal("Send error: %s", nng_strerror(rv));
		}

		nng_msleep(500);

	}

	// Wait a bit to give queues a chance to drain when the program exits.
	nng_msleep(200);
}









int
main_old()
{
	nng_socket sock = NNG_SOCKET_INITIALIZER;
	int        ret            = 0;

	//
	//  First we need some nng sockets. Not to be confused with network
	//  sockets
	//
	ret = nng_pub0_open(&sock);
	if (ret) {
		fatal("Failed to open socket: %s\n", nng_strerror(ret));
	}

	//
	//  Now we need to set up a listener for each socket so that they have
	//  addresses
	//

	nng_listener l;
	int async = 0;

	ret = nng_listener_create(&l, sock, PROXY_SEND_URL);
	if (ret != 0) {
		fatal("Unable to create listener for %s: %s",
				PROXY_SEND_URL, nng_strerror(ret));
	}
	
	
	ret  = nng_listener_start(l, async);
	if (ret != 0) {
		fatal("Failed to start listener for %s: %s\n",
				PROXY_SEND_URL, nng_strerror(ret));
	}

	//
	//  Finally let nng do the forwarding/proxying
	//

	// ret = nng_device(sock_front_end, sock_back_end);
	// panic_on_error(
	//     ret, "f-b nng_device returned %d: %s\n", ret, nng_strerror(ret));

	// sendloop(sock);

	sendloop_new(sock);

	printf("done");
	return 0;
}





int main_old_2(int argc, char* argv[]) {
	::jomoo::comm::PubSubClientServer pub_server;

	pub_server.init({
		.publisher_or_subscriber = ::jomoo::comm::PubSubClientServer::EnumPubSubType::PUBLISHER,
		.client_or_server = ::jomoo::comm::PubSubClientServer::EnumClientServerType::SERVER,
		.url = PROXY_SEND_URL,
		.sub_callback = {}
	});

	const char* data_template = "This is data to send with PubSubClientServer: A message from behind the Great Wall.\0";
	size_t datalen = strlen(data_template);
	uint32_t counter = 0;

	for (;;) {
		int          rv;
		nng_msg* msg;

		std::stringstream ss;
		ss << data_template << " " << (counter++);
		std::string data_str = ss.str();
		const char * data = data_str.c_str();
		datalen = data_str.size();

		if (0 != (rv = pub_server.publish(data, datalen))) {
			fatal("Send error: %d: %s", rv, nng_strerror(rv));
		}

		nng_msleep(500);
	}


	return 0;
}






int main(int argc, char* argv[]) {
	::jomoo::comm::PacketPubSubClientServer pub_server;

	pub_server.init({
		.publisher_or_subscriber = ::jomoo::comm::PubSubClientServer::EnumPubSubType::PUBLISHER,
		.client_or_server = ::jomoo::comm::PubSubClientServer::EnumClientServerType::SERVER,
		.url = PROXY_SEND_URL
	});

	::jomoo::comm::Publisher pub = pub_server.advertise<jomoo::utils::msg::MsgLakeTest>(TopicMsgLakeTest, 1);

	// const char* data_template = "This is data to send with PubSubClientServer: A message from behind the Great Wall.\0";
	// size_t datalen = strlen(data_template);
	uint32_t counter = 0;
	double a = 0;
	for (;;) {
		::jomoo::utils::msg::MsgLakeTest new_msg;
		new_msg.temperature = 10.0 + 32.0 * std::sin(a);
		new_msg.water_level = counter++;
		pub.publish(new_msg);
		a++;
		if (a >= 3.1415926535 * 200) {
			a = -3.1415926535 * 200;
		}

		nng_msleep(500);
	}


	return 0;
}